<?php
/**
 * This file contains the class AlertsModel which provides
 * most of the code requirements for the alerts page
 *
 * @copyright  2009 A Memory Tree
 * @license    A Memory Tree License
 */
/*. require_module 'pcre'; .*/
/**
 * This class provides the code for the alerts page
 *
 * @copyright  2009 A Memory Tree
 * @license    A Memory Tree License
 */
class AlertsModel
{
    /**
     * Access to the DB methods
     *
     * @var AlertsDB
     */
    private $_db;
    /**
     * Access to the View methods
     *
     * @var AlertsView
     */
    private $_view;
    /**
     * The id of the logged in user
     *
     * @var int
     */
    private $_userId;
    /**
     * Access to the Helper methods
     *
     * @var Helper
     */
    private $_helper;
    /**
     * Price per alert
     *
     * @var float
     */
    private $_price;
    /**
     * Extra for first alert
     *
     * @var float
     */
    private $_surcharge;
    /**
     * Total amount
     *
     * @var float
     */
    private $_total;
    /**
     * Corporate package price
     *
     * @var float
     */
    private $_package;
    /**
     * Access to the Session environment variables
     *
     * @var array[string]string
     */
    private $_session;
    /**
     * The form action that was performed
     *
     * @var string
     */
    private $_action;
    /**
     * The alert id that the action is performed against
     *
     * @var int
     */
    private $_alertId;
    /**
     * The alerts are ready to be ordered
     *
     * @var bool
     */
    private $_readyToOrder;
    /**
     * Create a new instance of this class
     *
     * @return void
     * @param AlertsDB $db
     * @param AlertsView $view
     * @param Helper $helper
     * @param array[string]mixed &$session
     */
    function __construct($db, $view, $helper, &$session)
    {
        $this->_db = $db;
        $this->_view = $view;
        $this->_helper = $helper;
        $this->_price = 5.00;
        $this->_surcharge = 4.90;
        $this->_package = 499.00;
        $this->_userId = 0;
        if (!empty($session['user'])) {
            $this->_userId = intval($session['user']);
        };
        $this->_action = '';
        $this->_alertId = 0;
    }
    /**
     * Interpret the instructed action
     *
     * @return string
     * @param string $instruction
     */
    function instructionAction($instruction)
    {
        $pattern = '/([^\\d]+)\\d+/';
        $action = preg_replace($pattern, '$1', $instruction);
        return $action;
    }
    /**
     * Interpret the instructed alert id
     *
     * @return int
     * @param string $instruction
     */
    function instructionAlertId($instruction) {
        $pattern = '/[^\\d]+(\\d+)/';
        $alertId = intval(preg_replace($pattern, '$1', $instruction));
        return $alertId;
    }
    /**
     * Get the form instruction
     *
     * @return string
     * @param array[string]mixed &$post
     */
    function getInstruction(&$post)
    {
        $instruction = '';
        $actions = array('new', 'add', 'order', 'package', 'edit', 'save', 'remove', 'confirmDelete', 'delete');
        foreach (array_keys($post) as $key) {
            $name = strval($key);
            $action = $this->instructionAction($name);
            if (in_array($action, $actions)) {
                $instruction = $name;
                break;
            }
            if (!empty($instruction)) {
                break;
            }
        }
        return $instruction;
    }
    /**
     * Provide an error message for a field
     *
     * @return array[string]string
     * @param string $type
     * @param string $message
     */
    function error($type, $message) {
        return array(
            'type' => $type,
            'message' => $message
        );
    }
    /**
     * Add an  unpaid alert
     *
     * @return string
     * @param int $userId
     * @param string $firstName
     * @param string $lastName
     */
    function addUnpaidAlert($userId, $firstName, $lastName)
    {
        
        $db = $this->_db;
        $view = $this->_view;
        $error = '';
        if (!empty($lastName)) {
            $success = $db->addUnpaidAlert($userId, $lastName, $firstName);
            if (!$success) {
                $error = $view->text('cannotSave');
            }
        } else {
            $error = $view->text('nameNotSaved');
        }
        return $error;
    }
    /**
     * Add an alert
     *
     * @return string
     * @param int $userId
     * @param string $firstName
     * @param string $lastName
     */
    function addPaidAlert($userId, $firstName, $lastName)
    {
        $db = $this->_db;
        $view = $this->_view;
        $error = '';
        if (!empty($lastName)) {
            $success = $db->addPaidAlert($userId, $lastName, $firstName);
            if (!$success) {
                $error = $view->text('cannotSave');
            }
        } else {
            $error = $view->text('nameNotSaved');
        }
        return $error;
    }
    /**
     * Save an unpaid alert
     *
     * @return string
     * @param int $alertId
     * @param string $firstName
     * @param string $lastName
     */
    function saveFullName($alertId, $firstName, $lastName)
    {
        $db = $this->_db;
        $view = $this->_view;
        $error = '';
        if (!empty($lastName)) {
            $success = $db->saveFullName($alertId, $firstName, $lastName);
            if (!$success) {
                $error = $view->text('cannotSave');
            }
        } else {
            $error = $view->text('nameNotSaved');
        }
        return $error;
    }
    /**
     * Save an alert that's been paid for
     *
     * @return string
     * @param int $alertId
     * @param string $firstName
     */
    function saveFirstName($alertId, $firstName)
    {
        $db = $this->_db;
        $view = $this->_view;
        $error = '';
        $success = $db->saveFirstName($alertId, $firstName);
        if (!$success) {
            $error = $view->text('cannotSave');
        }
        return $error;
    }
    /**
     * Delete an alert
     *
     * @return string
     * @param int $alertId
     */
    function deleteAlert($alertId)
    {
        $db = $this->_db;
        $view = $this->_view;
        $error = '';
        $success = $db->disableAlert($alertId);
        if (!$success) {
            $error = $view->text('cannotDelete');
        }
        return $error;
    }
    /**
     * Check that a person has agreed to the conditions
     *
     * @return string
     * @param string $agree
     */
    function confirmAgreement($agree)
    {
        $view = $this->_view;
        $error = '';
        if ($agree !== 'Yes') {
            $error = $view->text('mustAgree');
        }
        return $error;
    }
    /**
     * Process the alerts form
     *
     * @return array[string]string
     * @param array[string]mixed &$post
     */
    function process(&$post)
    {
        $db = $this->_db;
        $helper = $this->_helper;
        $userId = $this->_userId;
        $instruction = $this->getInstruction($post);
        $action = $this->instructionAction($instruction);
        $alertId = $this->instructionAlertId($instruction);
        if (empty($action)) {
            $action = $helper->get('action');
        }
        $this->_action = $action;
        $this->_alertId = $alertId;

        $firstName = trim($helper->post('firstname'));
        $lastName = trim($helper->post('lastname'));
        $agree = $helper->post('agree');
        $updates = array('new', 'add', 'save', 'order', 'package');
        $fieldError = '';
        $processError = '';
        if (in_array($action, $updates)) {
            if (isset($post['lastname'])) {
                if (empty($alertId)) {
                    if ($db->hasPackageRemaining($userId)) {
                        $processError = $this->confirmAgreement($agree);
                        if (empty($processError)) {
                            $db->decreaseRemainingPackage($userId);
                            $fieldError = $this->addPaidAlert($userId, $firstName, $lastName);
                        }
                    } else {
                        $fieldError = $this->addUnpaidAlert($userId, $firstName, $lastName);
                    }
                } else {
                    $fieldError = $this->saveFullName($alertId, $firstName, $lastName);
                }
            } else if (isset($post['firstname'])) {
                $fieldError = $this->saveFirstName($alertId, $firstName);
            }
        }
        $error = $this->error('', '');
        if (!empty($fieldError)) {
            $error = $this->error('field', $fieldError);
        } else {
            switch ($action) {
                case 'delete':
                case 'remove':
                    $processError = $this->deleteAlert($alertId);
                    break;
                case 'order':
                case 'package':
                    if (empty($fieldError)) {
                        $processError = $this->confirmAgreement($agree);
                    }
                    if (empty($fieldError) && empty($processError)) {
                        $this->_readyToOrder = TRUE;
                    }
                    break;
                default:
                    break;
            }
            if (!empty($processError)) {
                $error = $this->error('process', $processError);
            } else {
                if ($action === 'new') {
                    $this->_alertId = 0;
                }
            }
        }
        return $error;
    }
    /**
     * Get alerts for the page
     *
     * @return array[][string]string
     * @param int $userId
     */
    function getAlerts($userId)
    {
        $db = $this->_db;
        $alerts = $db->getAlerts($userId);
        return $alerts;
    }
    /**
     * Add one year to a given date
     *
     * @return string
     * @param string $date
     */
    function addOneYear($date)
    {
        $helper = $this->_helper;
        $time = strtotime($date);
        $addOneYear = 1;
        $newTime = $helper->changeTime($time, $addOneYear);
        return date('d M Y', $newTime);
    }
    /**
     * Get packages for the user
     *
     * @return array[int][string]string
     * @param int $userId
     */
    function getPackages($userId)
    {
        $db = $this->_db;
        $packages = /*.(array[int][string]string).*/ array();
        if ($db->hasPackage($userId)) {
            $packages = $db->getPackages($userId);
            $purchase = TRUE;
            if (count($packages) > 1) {
                $purchase = FALSE;
            }
            foreach ($packages as $key => $package) {
                $packages[$key]['expires'] = $this->addOneYear($package['purchased']);
                if ($purchase === TRUE && intval($package['remaining']) > 50) {
                    $purchase = FALSE;
                }
                $packages[$key]['purchase'] = strval($purchase);
            }
        }
        return $packages;
    }
    /**
     * Get packages for the user
     *
     * @return int
     * @param array[int][string]string $packages
     */
    function getRemaining($packages)
    {
        $remaining = 0;
        foreach ($packages as $key => $package)
        {
            $remaining += intval($package['remaining']);
        }
        return $remaining;
    }
    /**
     * Alerts for the page
     *
     * @return array[]string
     * @param array[][string]string $alerts
     * @param int $userId
     * @param bool $addOrder
     */
    function alertsPrice($alerts, $userId, $addOrder)
    {
        $db = $this->_db;
        $helper = $this->_helper;
        $prices = array();
        $price = $this->_price;
        $surcharge = $this->_surcharge;
        if ($db->hasPaid($userId)) {
            $surcharge = 0.00;
        }
        $packages = $this->getpackages($userId);
        $remaining = $this->getRemaining($packages);
        foreach ($alerts as $key => $alert) {
            $index = intval($key);
            $amount = 'Paid';
            if (empty($alert['paid'])) {
                if ($remaining > 0) {
                    $remaining -= 1;
                    $amount = 'Prepaid';
                } else {
                    $amount = $helper->money($price + $surcharge);
                    $this->_total += $price + $surcharge;
                    $surcharge = 0.00;
                }
            }
            $prices[$index] = $amount;
        }
        if ($addOrder) {
            $amount = '';
            if ($remaining > 0) {
                $remaining -= 1;
                $amount = 'Prepaid';
            } else {
                $this->_total += $price + $surcharge;
                $amount = $helper->money($price + $surcharge);
            }
            array_push($prices, $amount);
        }
        return $prices;
    }
    /**
     * Show a delete button, or if unpaid, a remove button.
     *
     * If the button has already been pressed, provide a confirm set of buttons instead.
     *
     * @return string
     * @param int $alertId
     * @param bool $paid
     * @param string $action
     */
    function deleteButton($alertId, $paid, $action)
    {
        $view = $this->_view;
        $deleteButton = '';
        if ($action === 'confirmDelete' && $alertId === $this->_alertId) {
            $deleteButton = $view->confirmDelete($alertId);
        } else if (!$paid) {
            $deleteButton = $view->removeAlertButton($alertId);
        } else {
            $deleteButton = $view->deleteAlertButton($alertId);
        }
        return $deleteButton;
    }
    /**
     * Provide the actions for an alert
     *
     * @return string
     * @param int $alertId
     * @param bool $paid
     * @param string $action
     */
     function alertActions($alertId, $paid, $action)
    {
        $view = $this->_view;
        $edit = $view->editAlertButton($alertId);
        if ($action === 'edit' && $alertId === $this->_alertId) {
            $edit = $view->saveAlertButton($alertId);
        }
        $deleteButton = $this->deleteButton($alertId, $paid, $action);
        return $edit.' '.$deleteButton;
    }
    /**
     * Create the alert rows
     *
     * @return string
     * @param array[][string]string $alerts
     * @param array $prices
     * @param string $action
     * @param bool $fieldError
     */
    function buildRows($alerts, $prices, $action, $fieldError)
    {
        $helper = $this->_helper;
        $view = $this->_view;
        $rows = '';
        foreach ($alerts as $key => $alert) {
            $alertId = intval($key);
            $lastName = $alert['lastName'];
            $firstName = $alert['firstName'];
            $purchased = $alert['purchased'];
            $expires = $this->addOneYear($purchased);
            $amount = $prices[$alertId];
            $paid = TRUE;
            if (intval($amount) > 0) {
                $paid = FALSE;
            }
            $buttons = $this->alertActions($alertId, $paid, $action);
            $editable = FALSE;
            if ($alertId === $this->_alertId) {
                if ($action === 'edit' || (
                    $action === 'save' && $fieldError === TRUE)) {
                    $editable = TRUE;
                }
            }
            $rows .= $view->alertRow($alertId, $alert, $expires, $paid, $amount, $buttons, $editable);
        }
        return $rows;
        
    }
    /**
     * Add order row
     *
     * @return string
     * @param float $price
     * @param string $action
     */
    function addOrderRow($price, $action)
    {
        $helper = $this->_helper;
        $view = $this->_view;
        $today = date('d M Y');
        $nextYear = $this->addOneYear($today);
        $amount = $helper->money($price);
        $addButton = $view->alertButton('add0', 'Add');
        $removeButton = $this->deleteButton(0, FALSE, $action);
        $buttons = $addButton . ' ' . $removeButton;
        return $view->addOrder($nextYear, $amount, $buttons);
    }
    /**
     * Alerts for the page
     *
     * @return string
     * @param array[][string]string $alerts
     * @param array $prices
     * @param bool $addOrder
     * @param string $action
     * @param int $alertId
     * @param bool $agree
     * @param float $total
     * @param array[int][string]string $packages
     * @param array[string]string $error
     */
    function alertsTable($alerts, $prices, $addOrder, $action, $alertId, $agree, $total, $packages, $error)
    {
        $helper = $this->_helper;
        $view = $this->_view;
        $rows = $this->buildRows($alerts, $prices, $action, $error['type'] === 'field');
        if ($error['type'] === 'field') {
            if ($action === 'add' || $action === 'new') {
                $addOrder = TRUE;
            }
        }
        $addOrderRow = '';
        if ($addOrder) {
            $price = floatval(end($prices));
            $addOrderRow = $this->addOrderRow($price, $action);
        }
        $totalAmount = $helper->money($total);
        $packageInfo = '';
        $purchasePackage = TRUE;
        if (count($packages) > 0) {
            foreach ($packages as $package) {
                $packageInfo .= $view->packageInfo($package['expires'], intval($package['remaining']), $helper->pluralise('alert', 'alerts', intval($package['remaining'])));
            }
            $purchasePackage = !empty($packages[0]['purchase']);
        }
        $packageRow = $view->packageRow($helper->money($this->_package), $alertId, $purchasePackage);
        $errorMessage = '';
        if (!empty($error['message'])) {
            $errorMessage = $view->error($error['message']);
        }
        $table = $view->alertTable($rows . $addOrderRow, $alertId, $agree, $totalAmount, $packageInfo, $packageRow, $errorMessage);
        return $table;
    }
    /**
     * Render the page
     *
     * @return string
     * @param array[string]mixed &$session
     * @param array[string]mixed &$post
     * @param array[string]string $error
     */
    function render(&$session, &$post, $error)
    {
        $helper = $this->_helper;
        $view = $this->_view;
        $userId = $this->_userId;
        $action = $this->_action;
        $alertId = $this->_alertId;
        $content = '';
        if (!empty($userId)) {
            $alerts = $this->getAlerts($userId);
            $addOrder = FALSE;
            if ($action === 'new' || count($alerts) === 0) {
                $addOrder = TRUE;
            }
            if (!empty($post['remove'])) {
                $addOrder = FALSE;
            }
            $agree = $helper->post('agree') === 'Yes';
            $prices = $this->alertsPrice($alerts, $userId, $addOrder);
            $total = (float)array_sum($prices);
            if ($this->_readyToOrder) {
                if ($action === 'order') {
                    if ($total > 0.00) {
                        header('Location: /orderAlerts.php?userid='.$userId);
                    } else {
                        $error = $this->error('process', $view->text('noAlerts'));
                    }
                } else if ($action === 'package') {
                    header('Location: /orderAlertsPackage.php?userid='.$userId);
                }
            }
            $packages = $this->getPackages($userId);
            $table = $this->alertsTable($alerts, $prices, $addOrder, $action, $alertId, $agree, $total, $packages, $error);
            $content = $view->content($table);
        }
        return $view->render($content);
    }
}
?>